package com.sunnystudio.mydiary.service;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.ActivityManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.IBinder;
import android.util.Log;

import com.airbiquity.android.choreofleetmessaging.CMessageDispatcher;
import com.airbiquity.android.choreofleetmessaging.SerialBroker;
import com.airbiquity.android.sfsp.AppHostMain;
import com.airbiquity.util.SystemManager;

/**
 * For configure USB network automatically
 * and make sure user can only access current application
 * and the navigation application it started.
 * 
 * @author nikm
 *
 */
public class DaemonService extends Service {
    public static final String ACTION_DAEMON = "com.airbiquity.android.sfsp.service.daemonService";
    public static final int CMD_APP_RESTART = 1;
    public static final int CMD_APP_GUARD = 2;
    public static final int CMD_USB_CONNECT = 3;
    public static final int CMD_USB_DISCONNECT = 4;
    
    private static final String TAG = "DaemonService";
    private CmdReceiver cmdReceiver;
    
    private static final int USB_NOT_CONNECTED = 0;
    private static final int SERIAL_DISCONNECTED = 0;
    private static final int USB_CONNECTED_NO_IP = 1;
    private static final int USB_CONNECTED = 2;
    private static final int SERIAL_CONNECTED = 1;

    private boolean mIsConnected = false;
    
    private int mIsUsbConnected = USB_NOT_CONNECTED;
    private int mIsSerialConnected = SERIAL_DISCONNECTED;
    
    private Timer mTimer1 = new Timer();
    private TimerTask mTimerTask1;
    private Timer mTimer2 = new Timer();
    private TimerTask mTimerTask2;
    
    private static final String USB_IP_ADDRESS = "10.0.0.100";
    
    private static final String[] allowAppList = {
	"com.alk.copilot",
	"geolife.android.navigationsystem",
	//"jackpal.androidterm.Term",
	//"com.android.settings.Settings",
	"com.airbiquity.android.sfsp.AppHostMain"};
    
    @Override
	public void onCreate() {
	Log.d(TAG, "--- Daemon service create ---");
	
	//setupUsbNetwork();
	
	mTimerTask1 = new TimerTask() {
		@Override
		    public void run() {
		    Log.d(TAG, "Daemon.TimerTask() pid,tid: " + android.os.Process.myPid() + "," + android.os.Process.myPid() );
		    testConnectionStatus();
		    /*
		    if (mIsUsbConnected == USB_CONNECTED_NO_IP) {
			setupUsbNetwork();
			mIsConnected = true;  // flag that we are connected now
		    }
		    */
		    /*
		    if (mIsSerialConnected == SERIAL_DISCONNECTED) {
			Log.d(TAG, "LEE: serial not connected");
		    } else if (mIsSerialConnected == SERIAL_CONNECTED) {
			Log.d(TAG, "LEE: serial now connected");
		    }
		    */
		}
	    };
	try {
	    mTimer1.schedule(mTimerTask1, 100, 1000);
	    //Log.d(TAG, "--- USB network task runing ---");
	} catch (Exception e) {
	    Log.e(TAG, "USB network task error: ", e);
	}
	
	cmdReceiver = new CmdReceiver();  
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_DAEMON); 
        registerReceiver(cmdReceiver, filter);
	
	super.onCreate();
    }
    
    @Override
	public int onStartCommand(Intent intent, int flags, int startId) {
	Log.d(TAG, "--- Daemon service start ---");
	/*
	if (mIsUsbConnected == USB_CONNECTED_NO_IP) {
	    setupUsbNetwork();
	}
	*/
	
	return START_STICKY;
    }
    
    @Override
	public void onDestroy() {
	Log.d(TAG, "--- Daemon service destory ---");
	
	mTimer1.cancel();
	mTimer1.purge();
	mTimer2.cancel();
	mTimer2.purge();
	this.unregisterReceiver(cmdReceiver);
	super.onDestroy();
    }
    
    @Override
	public IBinder onBind(Intent intent) {
	return null;
    }
    
    /**
     * Test the status of usb0 network
     */
    private void testConnectionStatus() {
	new Thread(new Runnable(){
		@Override
		    public void run() {
		    Process process = null;
		    InputStream in = null;		    
		    byte[] re = new byte[1024];
		    StringBuffer result = new StringBuffer(); 
		    
		    try {
			
			//Log.d(TAG, "LEE:mIsConnected=" + mIsConnected);
			// get the message broker from properties to see if it has changed
			String className = SystemManager.getInstance().getProperty("msg_broker", null);

			if (mIsConnected == false) { 
			    boolean mRestartCMessageDispatcher = false;

			    // first see if serial device is there
			    process = Runtime.getRuntime().exec("busybox lsusb");
			    in = process.getInputStream(); 
			    
			    while (in.read(re) != -1) { 
				result = result.append(new String(re)); 
			    }
			    
			    if (result.indexOf("ID 0403:6001") > 0) {
				mIsSerialConnected = SERIAL_CONNECTED;
				mIsConnected = true;

				// see if we already know we are using serial
				if (className != CMessageDispatcher.BROKER_SERIAL) {
				    SystemManager.getInstance().setProperty("msg_broker", CMessageDispatcher.BROKER_SERIAL );
				    //Log.d(TAG, "LEE: serial connected -- ");
				    mRestartCMessageDispatcher = true;  // no so restart CMessageDispatcher
				}

			    } else { // check for network
			    
				// Can not get differences when usb connected but no IP, by system "ifconfig" command.
				// Need to use shell commands from busybox.
				// Device should have beed rooted and installed busybox.
				process = Runtime.getRuntime().exec("busybox ifconfig usb0");
			    
				in = process.getInputStream(); 
				result.delete(0, result.length());  // clear out the previous result

				while (in.read(re) != -1) { 
				    result = result.append(new String(re)); 
				}
			    
				//		            Log.d(TAG, "Usb IP address: " + result.indexOf(USB_IP_ADDRESS));
				//		            Log.d(TAG, "Usb device usb0: " + result.indexOf("usb0"));
				//		            Log.d(TAG, "Usb device test result: " + result.toString());
			    
				if (result.indexOf(USB_IP_ADDRESS) > 0) {
				    mIsUsbConnected = USB_CONNECTED;
				    mIsConnected = true;

				    //Log.d(TAG, "LEE:USB_CONNECTED -- ");

				    // see if we already know we are using network
				    if (className != CMessageDispatcher.BROKER_NETWORK) {
					SystemManager.getInstance().setProperty("msg_broker", CMessageDispatcher.BROKER_NETWORK );
					mRestartCMessageDispatcher = true;  // no so restart CMessageDispatcher
				    }

				} else if(result.indexOf("usb0") == 0) {
				    //mIsUsbConnected = USB_CONNECTED_NO_IP;
				    mIsUsbConnected = USB_CONNECTED;

				    //Log.d(TAG, "LEE: USB_NO_IP_CONNECTED -- start network");

				    setupUsbNetwork();
				    mIsConnected = true;

				    // see if we already know we are using network
				    if (className != CMessageDispatcher.BROKER_NETWORK) {
					SystemManager.getInstance().setProperty("msg_broker", CMessageDispatcher.BROKER_NETWORK );
					mRestartCMessageDispatcher = true;  // no so restart CMessageDispatcher
				    }

				} else {
				    mIsUsbConnected = USB_NOT_CONNECTED;
				    //Log.d(TAG, "LEE: USB_NOT_CONNECTED -- ");
				}
			    }
			    if (mIsConnected == true && mRestartCMessageDispatcher == true) {
				Intent intent = new Intent();
				intent.setAction(AppHostMain.ACTION_APPHOSTMAIN);
				intent.putExtra("cmd", AppHostMain.APP_CMD_CMESSAGEDISPATCHER_RESTART);
				sendBroadcast(intent);
			    }

			}
			if (in != null)
			    in.close();
			result = null;
			
		    } catch (Exception e) {
			Log.d(TAG, "USB test exception: ", e);
		    } finally {
			if( null != process )
			    {
				process.destroy();
				process = null;
			    }
			else
			    {
				Log.d(TAG, "process is null in testConnectionStatus()");
			    }
		    }
		}
	    }).start();
    }
    
    
    /**
     * Setup USB network between device and OBU
     */
    private void setupUsbNetwork() {
	Log.d(TAG, "--- Setup usb network config ---");
	SystemManager.getInstance().execAsRoot("ifconfig usb0 "+ USB_IP_ADDRESS +" netmask 255.255.255.0 up", true);
    }
    
    /**
     * Test if the activity on stack top is in allowAppList
     * @param Context context
     * @return boolean
     */
    private boolean isAllow(Context context) {
	boolean isAllow = false;
	
	int maxNum = 1;
	ActivityManager activityManager = (ActivityManager) context
	    .getSystemService(ACTIVITY_SERVICE);
	
	List<ActivityManager.RunningTaskInfo> runningTasks = activityManager
	    .getRunningTasks(maxNum);
	
	if (runningTasks.isEmpty()) {
	    return false;
	}
	
	String currentActivity = runningTasks.get(0).baseActivity.getClassName();
	for (String app : allowAppList) {
	    if (currentActivity.startsWith(app)) {
		isAllow = true;
		break;
	    }
	}
	
	if (!isAllow) Log.d(TAG, "Not allowed application: " + runningTasks.get(0).baseActivity.getPackageName() + ", " + currentActivity);
	
	return isAllow;
	//return true;
    }
    
    /**
     * Check if webview is current active
     * 
     * @param context
     * @return true | false
     */
    private boolean isWebviewInForeground(Context context) {
	boolean isInForeground = false;
	
	int maxNum = 1;
	ActivityManager activityManager = (ActivityManager) context
	    .getSystemService(ACTIVITY_SERVICE);
	
	List<ActivityManager.RunningTaskInfo> runningTasks = activityManager
	    .getRunningTasks(maxNum);
	
	if (runningTasks.isEmpty()) {
	    return false;
	}
	
	String currentActivity = runningTasks.get(0).baseActivity.getClassName();
	if (currentActivity.equals("com.airbiquity.android.sfsp.AppHostMain")) {
	    isInForeground = true;
	}
	
	return isInForeground;
    }
    
    /**
     * @ClassName: CmdReceiver
     * @Description: 
     * Receive broadcast sent from activity, 
     * try to restart activity or reconnect USB network, according to cmd of intent.
     * 
     * @author nikm
     * @date 2012-9-25
     *
     */
    private class CmdReceiver extends BroadcastReceiver { 
        @Override  
	    public void onReceive(final Context context, Intent intent) {
	    
            String action = intent.getAction();
            Log.d(TAG, "--- Broadcast action in daemon service ---: " + action);
	    
	    if (ACTION_DAEMON.equals(action)) {
		int cmd = intent.getIntExtra("cmd", -1);
		Log.d(TAG, "--- cmd in daemon service ---: " + cmd);
		
		if (cmd == CMD_APP_RESTART && !isWebviewInForeground(context)) { // Restart webview or make it in foreground
		    Log.d(TAG, "--- Restart app ---");
		    Intent host = new Intent();
		    host.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		    host.setClass(context, AppHostMain.class);
		    context.startActivity(host);
		} else if (cmd == CMD_APP_GUARD) { // If current application is not in allowAppList, restart webview
		    Log.d(TAG, "--- Make app in foreground ---");
		    mTimer2.purge();
		    if (mTimerTask2 != null) mTimerTask2.cancel();
		    mTimerTask2 = new TimerTask() {
			    @Override
				public void run() {
				if (!isAllow(context)) { 
				    Log.d(TAG, "--- Restart webview ---");
				    
				    Intent host = new Intent();
				    host.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				    host.setClass(context, AppHostMain.class);
				    context.startActivity(host);
				    
				    mTimerTask2.cancel();
				}
			    }
			};
		    mTimer2.schedule(mTimerTask2, 100, 1000);
		} else if (cmd == CMD_USB_CONNECT) {
		    Log.d(TAG, "--- Usb connected ---");
		    
		    setupUsbNetwork();
		} else if (cmd == CMD_USB_DISCONNECT) {
		    Log.d(TAG, "--- Usb disconnected ---");
		    mIsUsbConnected = USB_NOT_CONNECTED;
		    mIsSerialConnected = SERIAL_DISCONNECTED;
		    mIsConnected = false;
		}
	    }
        }                       
    }
}